//---------------------------------------------------------------------
//  This file is part of the Background Motion solution.
// 
//  Copyright (C) Mindscape (TM).  All rights reserved.
//  http://www.mindscape.co.nz
// 
//  THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections;

namespace Mindscape.BackgroundMotion.Core.Model
{
  /// <summary>
  /// Base class for all units of work in the system
  /// </summary>
  public abstract class UnitOfWorkBase : IUnitOfWork
  {
    public event EventHandler Disposed;

    private readonly Hashtable _repositories = new Hashtable();

    private bool _disposed;

    /// <summary>
    /// Signals that the unit of work has completed successfully
    /// </summary>
    void IUnitOfWork.Complete()
    {
      EnsureNotDisposed();

      PerformComplete();

      Dispose();
    }

    /// <summary>
    /// Returns the instance of the repository associated with the generic type which is being used by this unit of work
    /// </summary>
    /// <returns>
    /// The instance of the repository handling the request
    /// </returns>
    /// <typeparam name="T">The generic type of the entity being persisted</typeparam>
    public IRepository<T> GetRepository<T>()
      where T : class, IIdentifiable
    {
      IRepository<T> repository = (IRepository<T>)_repositories[typeof(T)];

      if (repository == null)
      {
        repository = ServiceLocator.Get<IRepositoryFactory>().Create<T>();

        _repositories.Add(typeof(T), repository);
      }

      return repository;
    }

    /// <summary>
    /// Performs the complete.
    /// </summary>
    protected virtual void PerformComplete()
    {
    }

    /// <summary>
    /// Releases unmanaged resources and performs other cleanup operations before the
    /// <see cref="UnitOfWorkBase"/> is reclaimed by garbage collection.
    /// </summary>
    ~UnitOfWorkBase()
    {
      Dispose();
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    void IDisposable.Dispose()
    {
      Dispose();

      GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    private void Dispose()
    {
      if (!_disposed)
      {
        OnDisposed();

        _disposed = true;
      }
    }

    /// <summary>
    /// Called when [disposed].
    /// </summary>
    private void OnDisposed()
    {
      if (Disposed != null)
      {
        Disposed(this, EventArgs.Empty);
      }
    }

    /// <summary>
    /// Ensures that this unit of work has not been disposed.
    /// </summary>
    protected void EnsureNotDisposed()
    {
      if (_disposed)
      {
        throw new ObjectDisposedException(GetType().Name);
      }
    }
  }
}